/***************************************************************************/
/*                                                                         */
/*  pfrdrivr.c                                                             */
/*                                                                         */
/*    FreeType PFR driver interface (body).                                */
/*                                                                         */
/*  Copyright 2002, 2003, 2004, 2006, 2008 by                              */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include FT_SERVICE_PFR_H
#include FT_SERVICE_XFREE86_NAME_H
#include "pfrdrivr.h"
#include "pfrobjs.h"

#include "pfrerror.h"


FT_CALLBACK_DEF(FT_Error)
pfr_get_kerning(FT_Face pfrface,            /* PFR_Face */
                FT_UInt left,
                FT_UInt right,
                FT_Vector * avector)
{
    PFR_Face face = (PFR_Face)pfrface;
    PFR_PhyFont phys = &face->phy_font;


    pfr_face_get_kerning(pfrface, left, right, avector);

    /* convert from metrics to outline units when necessary */
    if (phys->outline_resolution != phys->metrics_resolution)
    {
        if (avector->x != 0)
            avector->x = FT_MulDiv(avector->x, phys->outline_resolution,
                                   phys->metrics_resolution);

        if (avector->y != 0)
            avector->y = FT_MulDiv(avector->x, phys->outline_resolution,
                                   phys->metrics_resolution);
    }

    return PFR_Err_Ok;
}


/*
 *  PFR METRICS SERVICE
 *
 */

FT_CALLBACK_DEF(FT_Error)
pfr_get_advance(FT_Face pfrface,            /* PFR_Face */
                FT_UInt gindex,
                FT_Pos * anadvance)
{
    PFR_Face face = (PFR_Face)pfrface;
    FT_Error error = PFR_Err_Invalid_Argument;


    *anadvance = 0;

    if (!gindex)
        goto Exit;

    gindex--;

    if (face)
    {
        PFR_PhyFont phys = &face->phy_font;


        if (gindex < phys->num_chars)
        {
            *anadvance = phys->chars[gindex].advance;
            error = 0;
        }
    }

Exit:
    return error;
}


FT_CALLBACK_DEF(FT_Error)
pfr_get_metrics(FT_Face pfrface,            /* PFR_Face */
                FT_UInt * anoutline_resolution,
                FT_UInt * ametrics_resolution,
                FT_Fixed * ametrics_x_scale,
                FT_Fixed * ametrics_y_scale)
{
    PFR_Face face = (PFR_Face)pfrface;
    PFR_PhyFont phys = &face->phy_font;
    FT_Fixed x_scale, y_scale;
    FT_Size size = face->root.size;


    if (anoutline_resolution)
        *anoutline_resolution = phys->outline_resolution;

    if (ametrics_resolution)
        *ametrics_resolution = phys->metrics_resolution;

    x_scale = 0x10000L;
    y_scale = 0x10000L;

    if (size)
    {
        x_scale = FT_DivFix(size->metrics.x_ppem << 6,
                            phys->metrics_resolution);

        y_scale = FT_DivFix(size->metrics.y_ppem << 6,
                            phys->metrics_resolution);
    }

    if (ametrics_x_scale)
        *ametrics_x_scale = x_scale;

    if (ametrics_y_scale)
        *ametrics_y_scale = y_scale;

    return PFR_Err_Ok;
}


FT_CALLBACK_TABLE_DEF
const FT_Service_PfrMetricsRec pfr_metrics_service_rec =
{
    pfr_get_metrics,
    pfr_face_get_kerning,
    pfr_get_advance
};


/*
 *  SERVICE LIST
 *
 */

static const FT_ServiceDescRec pfr_services[] =
{
    { FT_SERVICE_ID_PFR_METRICS, &pfr_metrics_service_rec },
    { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_PFR },
    { NULL, NULL }
};


FT_CALLBACK_DEF(FT_Module_Interface)
pfr_get_service(FT_Module module,
                const FT_String * service_id)
{
    FT_UNUSED(module);

    return ft_service_list_lookup(pfr_services, service_id);
}


FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec pfr_driver_class =
{
    {
        FT_MODULE_FONT_DRIVER |
        FT_MODULE_DRIVER_SCALABLE,

        sizeof(FT_DriverRec),

        "pfr",
        0x10000L,
        0x20000L,

        NULL,

        0,
        0,
        pfr_get_service
    },

    sizeof(PFR_FaceRec),
    sizeof(PFR_SizeRec),
    sizeof(PFR_SlotRec),

    pfr_face_init,
    pfr_face_done,
    0,                  /* FT_Size_InitFunc */
    0,                  /* FT_Size_DoneFunc */
    pfr_slot_init,
    pfr_slot_done,

    #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
    ft_stub_set_char_sizes,
    ft_stub_set_pixel_sizes,
    #endif
    pfr_slot_load,

    pfr_get_kerning,
    0,                  /* FT_Face_AttachFunc      */
    0,                   /* FT_Face_GetAdvancesFunc */
    0,                  /* FT_Size_RequestFunc */
    0,                  /* FT_Size_SelectFunc  */
};


/* END */